// Effective C++ 条款45：运用成员函数模板接受所有兼容类型
// 核心概念
// 条款45讨论了如何使用成员函数模板（member function templates）来实现泛化的拷贝构造和赋值操作，使类能够处理所有"兼容类型"的转换，同时保持类型安全。

// 问题背景
// 在C++中，我们经常需要处理不同但相关类型之间的转换。例如：
// 1.智能指针之间的转换：从SmartPtr<Derived>到SmartPtr<Base>
// 2.容器之间的转换：从vector<int>到vector<double>
// 3.数值类型之间的转换：从Complex<float>到Complex<double>
// 普通的构造函数和赋值操作符无法处理这些泛化的转换，因为它们需要在编译时知道确切的参数类型。

// 成员函数模板的解决方案
// 成员函数模板允许我们定义一族函数，而不仅仅是一个函数，从而能够处理各种兼容类型。
// 基本语法
template <typename T>
class MyClass
{
private:
    T value;

public:
    // 成员函数模板 - 泛化的拷贝构造函数
    template <typename U>
    MyClass(const MyClass<U> &other) : value(other.getValue()) {}

    // 成员函数模板 - 泛化的赋值操作符
    template <typename U>
    MyClass &operator=(const MyClass<U> &other)
    {
        value = other.getValue();
        return *this;
    }

    T getValue() const { return value; }
};

// 智能指针示例
// 以下是一个更实际的智能指针例子：
template <typename T>
class SmartPtr
{
private:
    T *pointee;

public:
    // 普通构造函数
    explicit SmartPtr(T *p = nullptr) : pointee(p) {}

    // 析构函数
    ~SmartPtr() { delete pointee; }

    // 成员函数模板 - 泛化的拷贝构造函数
    template <typename U>
    SmartPtr(const SmartPtr<U> &other)
        : pointee(other.get())
    { // 隐式转换 U* -> T*
      // 这里可能需要增加引用计数或复制资源
    }

    // 成员函数模板 - 泛化的赋值操作符
    template <typename U>
    SmartPtr &operator=(const SmartPtr<U> &other)
    {
        if (pointee != other.get())
        { // 避免自赋值
            delete pointee;
            pointee = other.get(); // 隐式转换 U* -> T*
            // 这里可能需要增加引用计数或复制资源
        }
        return *this;
    }

    // 访问器
    T *get() const { return pointee; }
};
// 这个实现允许从SmartPtr<Derived> 到SmartPtr<Base> 的转换，因为Derived *可以隐式转换为Base *。

// 类型安全与约束
// 成员函数模板的一个潜在问题是它们可能过于泛化，允许不应该允许的转换。我们可以通过几种方式增加约束：
// 1. 利用编译器的类型检查
template <typename T>
class SmartPtr
{
    // ...

    template <typename U>
    SmartPtr(const SmartPtr<U> &other)
        : pointee(other.get())
    { // 编译器会检查 U* 是否可转换为 T*
      // 如果U*不能转换为T*，编译器会报错。
    }

    // ...
};

// 普通函数与成员函数模板的关系
// 成员函数模板不会自动替代编译器生成的特殊成员函数。例如：
template <typename T>
class SmartPtr
{
    // ...

    // 成员函数模板 - 泛化的拷贝构造函数
    template <typename U>
    SmartPtr(const SmartPtr<U> &other);

    // 普通的拷贝构造函数 - 仍然需要显式声明
    // 如果没有声明普通的拷贝构造函数，编译器仍会生成一个，而不会使用成员函数模板。
    SmartPtr(const SmartPtr &other);

    // ...
};

// 实际应用示例
// 1. 标准库智能指针
// 标准库的shared_ptr和unique_ptr使用成员函数模板来支持派生类到基类的转换
// std::shared_ptr的简化版本
template <typename T>
class shared_ptr
{
public:
    // 普通构造函数
    explicit shared_ptr(T *p = nullptr);

    // 普通拷贝构造函数
    shared_ptr(const shared_ptr &other);

    // 成员函数模板 - 允许从shared_ptr<U>构造
    template <typename U>
    shared_ptr(const shared_ptr<U> &other);

    // 普通赋值操作符
    shared_ptr &operator=(const shared_ptr &other);

    // 成员函数模板 - 允许从shared_ptr<U>赋值
    template <typename U>
    shared_ptr &operator=(const shared_ptr<U> &other);

    // ...
};

// 2. 数值类型转换
template <typename T>
class Complex
{
private:
    T real, imag;

public:
    // 构造函数
    Complex(T r = 0, T i = 0) : real(r), imag(i) {}

    // 普通拷贝构造函数
    Complex(const Complex &other) : real(other.real), imag(other.imag) {}

    // 成员函数模板 - 允许从Complex<U>构造
    template <typename U>
    Complex(const Complex<U> &other) : real(other.getReal()), imag(other.getImag()) {}

    // 访问器
    T getReal() const { return real; }
    T getImag() const { return imag; }
};

// 使用示例
Complex<double> d(1.0, 2.0);
Complex<float> f(d); // 从double到float的隐式转换

// 3. 容器转换
template <typename T, typename Allocator = std::allocator<T>>
class MyVector
{
private:
    // ...

public:
    // 成员函数模板 - 从任何兼容的迭代器构造
    template <typename InputIterator>
    MyVector(InputIterator first, InputIterator last);

    // 成员函数模板 - 从其他MyVector<U>构造
    template <typename U, typename OtherAllocator>
    MyVector(const MyVector<U, OtherAllocator> &other);

    // ...
};

// 使用示例
MyVector<int> intVec = {1, 2, 3};
MyVector<double> doubleVec(intVec.begin(), intVec.end()); // 使用迭代器构造
MyVector<long> longVec(intVec);                           // 使用成员函数模板构造
